Skip to content

WebWorker 基础

WebWorker 的作用

  • JS 是单线程,复杂计算会卡住页面
  • 而 Web Worker 可以开一个后台线程,不阻塞 UI
  • 也就是复杂计算可以交给 WebWorker 去做,以此优化 UI 卡顿
  • 注意:不能操作 DOM,只能通过 postMessage 通信,且通信是拷贝传递(结构化克隆),不是共享

WebWorker 核心语法

shell
# 创建
new Worker('worker.js') 

# 发送
worker.postMessage(数据) 

# 接收
worker.onmessage = fn 

# 关闭
worker.terminate()

实际用途

shell
# 适合
大量CPU 密集型计算,不阻塞 UI 渲染
后台异步处理,页面照常交互
数据解析、转换、加工
大文件处理、分片、校验
定时 / 循环任务,不卡页面

# 不适合
操作 DOM、访问 window/document
频繁、极轻量的小计算(通信开销更大)
直接操作 localStorage/indexedDB(可发消息让主线程做)
弹框、路由跳转、UI 相关逻辑

# 总结
凡是算得多、跑得久、不碰 DOM的任务,都适合丢给 WebWorker。

典型业务场景

shell
大数据量表格排序、筛选、聚合计算
复杂图表数据预处理
大量 JSON/XML/Excel 解析与格式化
前端加密、解密、签名计算
图片 / 音频前端压缩、格式转换
大文件MD5/SHA 校验、分片上传计算
长列表虚拟滚动数据预处理
复杂数学公式、物理模拟、3D 计算
日志 / 埋点数据本地批量统计
爬虫类数据抓取与解析(同域下)
后台定时数据同步、缓存更新
代码编辑器语法检查、格式化
大量正则匹配、文本替换、分词处理
游戏引擎物理计算、AI 逻辑
音视频转码、切片、帧处理
在线文档协同编辑冲突计算

注意

测试的时候不能使用本地的html文件, 需要启动本地服务:http-server 或者放在启动本地环境的 vue/react 项目中测试


通信一则

主线程与 Worker 之间只能用 postMessage / onmessage 交换数据;载荷使用 结构化克隆算法 拷贝(函数、Symbol、部分内置对象不可克隆)。需要共享大块缓冲区时可考虑 Transferable(如 ArrayBuffer)减少拷贝开销。


Vite 与 Vue3:内联多 Worker

无需单独 worker.js 文件时,可用 Blob + URL.createObjectURL 动态生成 Worker,便于在单文件组件里调试。多个 Worker 可并行分担 CPU 密集任务,主线程汇总结果。

示例:三段区间并行累加

html
<template>
  <div class="p-6">
    <h2>Vue3 + 多 Web Worker 并发计算</h2>
    <p class="mt-4">总计算结果:{{ total }}</p>
    <button @click="startCalc" class="mt-4 px-4 py-2 bg-blue-500 text-white">
      开始计算
    </button>
  </div>
</template>

<script setup>
import { ref } from "vue";

const total = ref(0);

function createInlineWorker(workerFunc) {
  const blob = new Blob([`(${workerFunc.toString()})()`], {
    type: "application/javascript",
  });
  return new Worker(URL.createObjectURL(blob));
}

const workerLogic = () => {
  self.onmessage = (e) => {
    const { start, end } = e.data;
    let sum = 0;
    for (let i = start; i <= end; i++) {
      sum += i;
    }
    self.postMessage({ result: sum });
  };
};

const startCalc = () => {
  const results = [];
  let finishedCount = 0;

  const w1 = createInlineWorker(workerLogic);
  const w2 = createInlineWorker(workerLogic);
  const w3 = createInlineWorker(workerLogic);

  w1.postMessage({ start: 1, end: 1000000 });
  w2.postMessage({ start: 1000001, end: 2000000 });
  w3.postMessage({ start: 2000001, end: 3000000 });

  function onMessage(e) {
    results.push(e.data.result);
    finishedCount++;
    if (finishedCount === 3) {
      total.value = results.reduce((a, b) => a + b, 0);
      w1.terminate();
      w2.terminate();
      w3.terminate();
    }
  }

  w1.onmessage = onMessage;
  w2.onmessage = onMessage;
  w3.onmessage = onMessage;
};
</script>

三段结果分别为 50000050000015000005000002500000500000,相加得 4500001500000。生产环境若构建工具支持(如 Vite ?worker),优先独立 Worker 文件以便浏览器缓存与 Tree-shaking。